/* ************************************************************************
> File Name:     4.c
> Author:        zhfu
> mail:          3346897597@qq.com
> Created Time:  2022年05月10日 星期二 16时03分58秒
> Description:   
 ************************************************************************/
#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>
#include<wait.h>
#include<sys/stat.h>
#include<fcntl.h>
#define N 20 /*命令行中参数的最大个数 cd /home的参数个数是2*/
#define M 80 /*命令行中参赛的最大长度cd /home的参数长度分别是3和6（包括\0）*/

void mal_arr(char **argv);
void free_arr(char **argv);
int is_symbol_in(char *src, char sym);
int change_in_out(char **argv);

int main(void)
{
    pid_t pid;
    char *argv[N];
    int i;
    
    mal_arr(argv);

    return 0;
}

void mal_arr(char **argv)
{
    char s[M];
    int i;
    pid_t pid_arr[2], pid;

    while (1){
        printf("%s", "$");
        i = 0;
        while (scanf("%s", s) == 1){
            argv[i] = malloc(M);
            strncpy(argv[i], s, M);
            ++i;

            char c;
            while ((c = getchar()) == ' ');
            if (c == '\n'){
                break;
            }
            else{
                ungetc(c, stdin);
            }
        }
        argv[i] = NULL;
    
        int key = 0;

        i = 0;
        while (argv[i]){
            if (is_symbol_in(argv[i], '|') >= 0){
                key = 1;
                break;
            }
            ++i;
        }

        char *argvp[N];
        memcpy(argvp, argv, sizeof(char *) * N);

        if (key){
            int fd[2];
            if (pipe(fd) < 0){
                perror("pipe error");
                exit(1);
            }

            char *argv1[N], *argv2[N];
            int i;
            int pos;
            for (i = 0; (pos = is_symbol_in(argv[i], '|')) == -1; ++i){
                argv1[i] = argv[i];
            }
            int j = 0;

            if (argv[i][pos+1] == '\0' && argv[i][0] != '|'){ /*cat < file1| wc -c > file1*/
                argv[i][pos] = '\0';
                argv1[i] = argv[i];
                ++i;
                argv1[i] = NULL;
            }
            else if (argv[i][0] == '|' && argv[i][1] == '\0'){ /*cat < file1 | wc -c > file1*/
                argv1[i] = NULL;
                ++i;
            }
            else if (argv[i][0] == '|' && argv[i][1] != '\0'){ /*cat < file1 |wc -c > file1*/
                argv1[i] = NULL;
                argv[i] += 1;
            }
            else{/*cat < file1|wc -c >file1*/
                argv[i][pos] = '\0';
                argv1[i] = argv[i];
                argv1[i+1] = NULL;
                argv[i] += pos + 1;
            }

            while (argv[i]){
                argv2[j] = argv[i];
                ++i;
                ++j;
            }
            argv2[j] = NULL;

            for (i = 0; i < 2; ++i){
                pid_arr[i] = fork();
                
                if (pid_arr[i] == -1){
                    perror("fork error:");
                    exit(1);
                }
                if (pid_arr[i] == 0){
                    break;
                }
            }

            if (i == 0){
                close(fd[0]);
                int p;
                p = change_in_out(argv1);
                if (p != -1){
                    argv1[p] = NULL;
                }
                dup2(fd[1], STDOUT_FILENO);
                execvp(argv1[0], argv1);
            }
            if (i == 1){
                close(fd[1]);
                int p;
                p = change_in_out(argv2);
                if (p != -1){
                    argv2[p] = NULL;
                }
                dup2(fd[0], STDIN_FILENO);
                execvp(argv2[0], argv2);
            }

            int set1, set2;
            if (pid_arr[0] > 0 && pid_arr[1] > 0){
                close(fd[0]);
                close(fd[1]);
                do{
                    set1 = waitpid(pid_arr[0], NULL, WNOHANG);
                    set2 = waitpid(pid_arr[1], NULL, WNOHANG);
                }while (set1 == 0 || set2 == 0);
            }
        }
        else{
            pid = fork();
            if (pid < 0){
                perror("fork");
                exit(1);
            }
            if (pid == 0){
                int p;
                p = change_in_out(argv);
                if (p != -1){
                    argv[p] = NULL;
                }
                execvp(argv[0], argv);
            }

            int set;
            do{
                set = waitpid(-1, NULL, WNOHANG);
            }while (set == 0);
        }
        free_arr(argvp);
    }

    i = 0;
    while (argv[i]){
        printf("%s ", argv[i]);
        ++i;
    }
}

void free_arr(char **argv)
{
    int i = 0;
    while (argv[i]){
        free(argv[i]);
        ++i;
    }
}

int is_symbol_in(char *src, char sym)
{
    int i = 0;
    while (src[i]){
        if (src[i] == sym){
            return i;
        }
        ++i;
    }

    return -1;
}

int change_in_out(char **argv)
{
    int i = 0;
    int pos1 = 0, pos2 = 0, fd, key1 = -1, key2 = -1;
    while (argv[i]){
        if ((pos1 = is_symbol_in(argv[i], '<')) != -1){
            if (argv[i][pos1+1]){
                fd = open(argv[i]+pos1+1, O_RDONLY);
                if (fd < 0){
                    perror("open");
                    exit(1);
                }
                dup2(fd, STDIN_FILENO);
                close(fd);
                if (pos1 != 0){/*ls -l -R>file1*/
                    argv[i][pos1] = '\0';
                    key1 = i + 1;
                }
                else{ /*ls -l -R >file1*/
                    key1 = i;
                }
            }
            else{
                fd = open(argv[i+1], O_RDONLY);
                if (fd < 0){
                    perror("open");
                    exit(1);
                }
                dup2(fd, STDIN_FILENO);
                close(fd);
                if (pos1 != 0){/*ls -l -R> file1*/
                    argv[i][pos1] = '\0';
                    key1 = i + 1;
                }
                else{ /*ls -l -R > file1*/
                    key1 = i;
                }
            }
        }

        if ((pos2 = is_symbol_in(argv[i], '>')) != -1){
            if (argv[i][pos2+1]){
                fd = open(argv[i]+pos2+1, O_WRONLY | O_CREAT | O_TRUNC, 0666);
                if (fd < 0){
                    perror("open");
                    exit(1);
                }
                dup2(fd, STDOUT_FILENO);
                close(fd);
                if (pos2 != 0){/*cat<file1*/
                    argv[i][pos2] = '\0';
                    key2 = i + 1;
                }
                else{ /*cat <file1*/
                    key2 = i;
                }
            }
            else{
                fd = open(argv[i+1], O_WRONLY | O_CREAT | O_TRUNC, 0666);
                if (fd < 0){
                    perror("open");
                    exit(1);
                }
                dup2(fd, STDOUT_FILENO);
                close(fd);
                if (pos2 != 0){/*cat< file1*/
                    argv[i][pos2] = '\0';
                    key2 = i + 1;
                }
                else{ /*cat < file1*/
                    key2 = i;
                }
            }
        }
        ++i;
    }

    if (key1 == -1)
        key1 = 0;
    if (key2 == -1)
        key2 = 0;

    if (key1 && key2){
        return key1 < key2 ? key1 : key2;
    }
    else if (key1){
        return key1;
    }
    else if (key2){
        return key2;
    }

    return -1;
}
